﻿using System;
using System.Linq;
using System.Threading;
using COFE.Core.Profile;
using COFE.Data.Profile;
using COFE.Data.Lister;
using COFE.Core;
using COFE.Core.EntryType;
using COFE.Core.Actions;
using COFE.Data.Utils;
using COFE.Data.Filter;
using COFE.Core.Utils;
using COFE.Core.Filter;

namespace COFE.Data
{
    public static class COFEDBShared
    {
        #region Constructor

        static COFEDBShared()
        {
            TTLPropertyValues = TimeSpan.FromDays(2);
            TTLEntryExist = TimeSpan.FromDays(2);
            TTLEntryList = TimeSpan.FromDays(2);
            TTLUserExpire = TimeSpan.FromDays(2);
            DTMin = new DateTime(1990, 1, 1, 12, 0, 0);
            if (!String.IsNullOrEmpty(COFEDBConfiguration.Config.ConnectionString))
                _connectionString = COFEDBConfiguration.Config.ConnectionString;

            PasswordEncoder = new NoPasswordEncoder();
            DBEntryManager = new DBEntryManager();
            DBEntryPropertyManager = new DBEntryPropertyManager();
        }

        #endregion

        #region Methods

        public static void Register(string connectionString, bool schedulerPaused)
        {
            _connectionString = connectionString;

            COFEShared.VolumeRegistrar.RegisterFactory(new COFE.Data.DBLink.DBLinkFactory("DBLINK"));
            COFEShared.PropertyDictionary.RegisterProperties<DatabaseProperties>();

            COFEShared.PropertyDictionary = new DBPropertyDictionary();
            COFEShared.VolumeRegistrar = new DBVolumeRegistrar();
            COFEShared.PathParser = new DBPathParser();
            COFEShared.EntryConstructor = new DBEntryConstructor();
            COFEShared.EntryListRegistrar = new DBEntryListRegistrar();
            COFEShared.UserProfileManager = new DBUserProfileManager();
            COFEShared.EntryTypeDictionary = new DBEntryTypeDictionary(new DBEntryIconExtractor(), new EntryTypeFilterGenerator());

            COFEActionShared.WorkScheduler = new DBWorkScheduler();
            if (schedulerPaused)
                COFEActionShared.WorkScheduler.Pause();
            COFEShared.MasterEventLogger.RegisterEventLoggers(new DBWorkEventLogger());
            COFEShared.MasterEventLogger.RegisterEventLoggers(new DBFileSystemEventLogger());

            FilterUtils2<IEntryFilter>.RegisterFilter(typeof(DBExpireEntryFilter)
                , (id, param) => new DBExpireEntryFilter(param, id));

            DBFilterUtils.RegisterFilterExpression(new DBExpireEntryFilterExpression());
            DBFilterUtils.RegisterFilterExpression(new RootEntryFilterExpression());
            DBFilterUtils.RegisterFilterExpression(new FileTypeEntryFilterExpression());
            DBFilterUtils.RegisterFilterExpression(new FileNameEntryFilterExpression());
            DBFilterUtils.RegisterFilterExpression(new GuidEntryFilterExpression());
            DBFilterUtils.RegisterFilterExpression(new OrEntryFilterExpression());
            DBFilterUtils.RegisterFilterExpression(new PropertyEntryFilterExpression());
            DBFilterUtils.RegisterFilterExpression(new SortResultOptionFilterExpression());
            DBFilterUtils.RegisterFilterExpression(new PaginateOptionFilterExpression());
        }

        private static bool _checkDBValid = false;

        public static COFEDB2 CreateContext()
        {
            var context = _connectionString == null ? new COFEDB2() : new COFEDB2(_connectionString);

            if (!_checkDBValid)
                if (!context.Entries.Any(e => e.EntryId == Guid.Empty))
                {
                    throw new Exception("Database not initaliated correctly, rootentry doesn't exists!");
                }
                else _checkDBValid = true;


            if (COFEDBConfiguration.Config.Sqlite_EnableForeignKey)
                context.Connection.StateChange += (o, e) =>
                {
                    if (e.CurrentState == System.Data.ConnectionState.Open)
                        context.ExecuteStoreCommand("PRAGMA foreign_keys = true;");
                };

            return context;
        }






        #endregion

        #region Data

        static string _connectionString = null;
        static IDBEntryManager _dbEntryManager = null;
        static IDBEntryPropertyManager _dbEntryPropertyManager = null;
        static IDBOperationProvider _dbOpterations = new DBOperationProvider();
        static IDBEntryOperationProvider _dbEntryOperations = new DBEntryOperationProvider();
        //static ThreadLocal<COFEDB2> _context = createContext();
        //static ReaderWriterLockSlim _contextLockGlobal = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
        static ThreadLocal<ReaderWriterLockSlim> _contextLock =
            new ThreadLocal<ReaderWriterLockSlim>(() => new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion));


        #endregion

        #region Public Properties

        public static TimeSpan TTLPropertyValues { get; set; }
        public static TimeSpan TTLEntryExist { get; set; }
        public static TimeSpan TTLEntryList { get; set; }
        public static TimeSpan TTLUserExpire { get; set; }
        public static DateTime DTMin { get; set; }

        public static EventHandler OnDBEntryManagerChanged = (o, e) => { };
        public static EventHandler OnDBEntryPropertyManagerChanged = (o, e) => { };

        public static IDBOperationProvider DBOperations
        {
            get { return _dbOpterations; }
            set { _dbOpterations = value; }
        }

        public static IDBEntryOperationProvider DBEntryOperations
        {
            get { return _dbEntryOperations; }
            set { _dbEntryOperations = value; }
        }

        public static IDBEntryManager DBEntryManager
        {
            get { return _dbEntryManager; }
            set { _dbEntryManager = value; OnDBEntryManagerChanged(null, EventArgs.Empty); }
        }

        public static IDBEntryPropertyManager DBEntryPropertyManager
        {
            get { return _dbEntryPropertyManager; }
            set { _dbEntryPropertyManager = value; OnDBEntryPropertyManagerChanged(null, EventArgs.Empty); }
        }



        public static IPasswordEncoder PasswordEncoder { get; set; }

        //public static COFEDB2 Context { get { return _context.Value; } }
        public static ReaderWriterLockSlim ContextLock { get { return _contextLock.Value; } }
        //public static ReaderWriterLockSlim ContextLockGlobal { get { return _contextLockGlobal; } }

        #endregion

    }
}
